import traceback

from apps.notify.actions import (
    do_set_vul_verification,
    do_send_completed_email,
    do_send_completed_inbox_mail,
    do_set_target_title,
    do_disable_target_groups,
    do_push_completed,
    do_save_current_version,
    do_set_is_failed,
    do_destroy_tasks,
)
from models.task import ScanEvents, ScanTaskSessions
from models.target import Targets, TargetGroups
from apps.target.serializer import SerializerTargetGroup
from apps.warn_center.serializer import FakeRequest
from apps.global_config.serializer import get_global_config
from apps.system_manage.views import DDiskUsageView
from apps.notify.notify_log import logger
from utilities.enums import EXTaskType, TaskType
from utilities.task_config import PARSER_MAP, EX_TASK_TYPE_TUPLE
from utilities.utils import (
    get_event_email_data_availability,
    get_event_email_data,
    EventParser,
)
from utilities.redis import notify_redis
from utilities.djconsole import djconsole


REDIS_PREFIX = 'notify'


def notify_queued(data):
    task_session_id = data.get('task_session_id')
    task = data.get('task', {})
    update_info = djconsole.get_update_version(FakeRequest())

    tmp_dict = {
        'task_session_id': task_session_id,
        'user_id': task.get('user_id'),
        'target_id': task.get('target_id'),
        'data_version': update_info.get('data_version'),
        'system_version': update_info.get('system_version'),
    }

    try:
        do_save_current_version(task_session_id, tmp_dict)
    except Exception:
        traceback.print_exc()


def notify_completed(data):
    addition = data.get('task', {}).get('addition', {})
    task_session_id = data.get('task_session_id')
    task_id = data.get('task_id')
    task_type = addition.get('task_type')
    target_id = data.get('task', {}).get('target_id')
    task = data.get('task', {})
    safety = False

    obj_task_session = ScanTaskSessions.objects.filter(
        task_session_id=task_session_id
    ).first()
    obj_events = ScanEvents.objects.filter(
        task_session_id=obj_task_session.task_session_id
    )
    obj_target = Targets.objects.filter(target_id=target_id).first()
    if not obj_target:
        # 不存在的 target
        return

    if task_type == EXTaskType.vul_verification_task.value:
        verification_detail = None
        for obj_event in obj_events:
            if obj_event.event_type != 4:
                verification_detail = obj_event.detail
                break
        do_set_vul_verification(task_id, addition.get('event_id'), verification_detail)
        return
    if obj_events and task_type == EXTaskType.target_info.value:
        do_set_target_title(
            target_id, obj_events[0].detail.get('basic_info', {}).get('title', '')
        )
        return

    # 更新、删除变更监测基准 任务完成后需要删除任务
    if task_type == EXTaskType.change_check_config.value:
        do_destroy_tasks([task_id])
        return

    obj_target_group = TargetGroups.objects.filter(
        target_group_id=obj_target.target_group_id
    ).first()

    # check license
    check_pass_session = check_license_max_task_session()
    check_pass_expired = check_license_expired()
    if not check_pass_session or not check_pass_expired:
        if notify_redis.set(
            f"{REDIS_PREFIX}:disabling_all_targets_group", 1, ex=120, nx=True
        ):
            do_disable_target_groups(
                TargetGroups.objects.filter(task_config__is_periodic=True)
            )
            if not check_pass_session:
                logger.info("License expired, disabled all target groups.")
            if not check_pass_expired:
                logger.info(
                    "Task session retched the limit, disabled all target groups. "
                )

        # do_remove_task_session(task_session_id)
        # logger.info(f"Task session retched the limit, remove current task_session")
        return

    parser = PARSER_MAP.get(task_type)()

    # if task_type != TaskType.availability.value:
    parser.set_events([item.to_dict() for item in obj_events])

    if task_type not in (TaskType.availability.value, *EX_TASK_TYPE_TUPLE):
        gc = get_global_config()
        gc.update(inc__task_session_count=1)

    task_config = obj_target_group.task_config
    if obj_target.task_config.is_solo:
        task_config = obj_target.task_config
    if not getattr(task_config.warn_info, task_type, False):
        return

    if task_type == TaskType.availability.value:
        do_set_is_failed(obj_task_session)
        is_check_availability = True if not obj_target.task_config.availability.is_disabled else False
        is_check_cloud = obj_target.job_config_map.availability.use_cloud or False
        is_cloud = check_license_is_cloud()
        normal_status = parser.get_normal(
            obj_task_session.job_config_map.get('site_info', {}), obj_target, is_cloud
        ).get('normal_status', 0)
        if normal_status in [0, 1]:
            safety = True
        content = get_event_email_data_availability(parser, is_check_availability, is_check_cloud) 
    else:
        data = EventParser([parser], use_fill=False).get()
        task_type_event_name_count_map = data.get('task_type_event_name_count_map', {})
        content = get_event_email_data(
            task_type, task_type_event_name_count_map.get(task_type, {})
        )
        severity_name_count_map = (
            EventParser([parser]).get().get('severity_name_count_map', {})
        )
        severity_name_count_map.pop("UNKNOWN", 0)
        if not sum(severity_name_count_map.values()):
            safety = True

    if not safety:
        do_send_completed_email(
            task, obj_target, obj_target_group, obj_task_session, content
        )
    else:
        content['inbox_content'] = "处于安全状态"

    do_send_completed_inbox_mail(
        task, content, obj_task_session.task_config.get('is_periodic', True)
    )


def notify_disk_usage(data):
    master = data.get('master', 0)
    fake_request = FakeRequest()
    setattr(fake_request, 'query_params', {'master': master})
    DDiskUsageView.check_usage(fake_request, DDiskUsageView)


def check_license_max_task_session() -> bool:
    """

    :return: True: not reached max task session.
    """
    license_info = djconsole.get_license_detail(FakeRequest())
    return not SerializerTargetGroup.is_max_task_session(license_info)[0]


def check_license_expired() -> bool:
    """

    :return: True: not expired, False expired.
    """
    license_info = djconsole.get_license_detail(FakeRequest())
    return not license_info.get('is_expired', True)


def check_license_is_cloud() -> bool:
    """

    :return: True: has cloud, False no cloud.
    """
    license_modules = djconsole.get_license_detail(FakeRequest()).get('modules', [])
    return 'cloud' in license_modules


RECEIVE_NOTIFY = {
    'NT_TASK_QUEUED': notify_queued,
    # 'NT_TASK_PROCESSING': notify_processing,
    'NT_TASK_COMPLETED': notify_completed,
    # 'NT_TASK_ABORTED': notify_aborted,
    # 'NT_TASK_FAILED': notify_failed,
    'NT_SYS_DISK_USAGE': notify_disk_usage,
}

PUSH_NOTIFY = {
    'NT_TASK_COMPLETED': do_push_completed,
}

FAILED_CONDITIONS = ()
